package com.schedualnew.mq.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import cn.hutool.json.JSONUtil;
import com.schedualnew.mq.config.ApplyMQConfig;
import com.schedualnew.mq.config.AutoScheduleProperties;
import com.schedualnew.mq.entity.*;
import com.schedualnew.mq.entity.vo.autoschedule.ScheduleApmReqVO;
import com.schedualnew.mq.entity.vo.autoschedule.ScheduleApmResVO;
import com.schedualnew.mq.entity.vo.autoschedule.ScheduleCommonResVO;
import com.schedualnew.mq.mapper.*;
import com.schedualnew.mq.util.DataTrans;
import com.schedualnew.mq.util.DateUtils;
import com.schedualnew.mq.util.HttpUtils;
import com.schedualnew.mq.util.JsonUtil;
import com.schedualnew.mq.yihuiesb.model.EsbMsgParser;
import com.schedualnew.mq.yihuiesb.model.EsbReceiveMsg;
import com.schedualnew.mq.yihuiesb.util.FieldConfigUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ApplyService {
    private Logger logger = LogManager.getLogger(ApplyService.class);
    //private ExecutorService executor = Executors.newCachedThreadPool();
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 8, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    @Autowired
    private ExamApplyMapper examApplyMapper;
    @Autowired
    private ExamApplyPatientMapper examApplyPatientMapper;
    @Autowired
    private ExamApplyItemMapper examApplyItemMapper;
    @Autowired
    private ExamApplyOrganMapper examApplyOrganMapper;
    @Autowired
    private ExamScheduleMapper examScheduleMapper;
    @Autowired
    private ExamSysLogMapper examSysLogMapper;
    @Autowired
    private CommonService commonService;
    @Autowired
    private ApplyMQConfig applyMQConfig;
    @Autowired
    private FieldConfigUtil fieldConfigUtil;
    @Autowired
    private DictExamItemMapper dictExamItemMapper;

    /**
     * 处理申请消息
     *
     * @param applyContent           消息内容xml
     * @param msgId                  消息id
     * @param applyBackhaulQueueName
     * @param applyReturnMsg
     * @return
     */
    public boolean handleApplyMsg(String applyContent, String msgId, String applyBackhaulQueueName, String applyReturnMsg) {
        StringBuffer parseResultBuffer = new StringBuffer();
        EsbReceiveMsg esbEntry = EsbMsgParser.parseCommonEsbMsg(applyContent, parseResultBuffer);

        // 记录转换后的实体
        logger.info(JSONUtil.toJsonStr(esbEntry));
        if (esbEntry != null) {
            int nApplyCount = esbEntry.getMsgInfo().getMsg().getDetails().getContentList().size();
            logger.info("共{}条数据", nApplyCount);
            StringBuffer resultDesc = new StringBuffer();

            List<ApplyInfo> applyInfos = new ArrayList<>();
            List<Map<String, String>> applyInfoMaps = new ArrayList<>(nApplyCount);
            // 先解析所有的申请单列表
            for (int reqIndex = 0; reqIndex < nApplyCount; reqIndex++) {
                Map<String, String> applyInfoMap = new HashMap<>();
                String detail = esbEntry.getMsgInfo().getMsg().getDetails().getContentList().get(reqIndex);
                try {
                    if (EsbMsgParser.parseApplyDetailMsg(detail, applyInfoMap)) {
                        ApplyInfo applyInfo = new ApplyInfo();
                        convertApplyInfo(false, applyInfoMap, applyInfo);
                        applyInfos.add(applyInfo);
                        applyInfoMaps.add(applyInfoMap);
                    } else {
                        logger.error("解析申请单消息失败：{}\n" + detail);
                        applyInfos.add(null);
                        applyInfoMaps.add(null);
                    }
                } catch (Exception e) {
                    logger.error("解析申请单消息失败：\n" + applyContent, e);
                    applyInfos.add(null);
                    applyInfoMaps.add(null);
                }
            }

            String detail = "";
            for (int nApplyIndex = 0; nApplyIndex < nApplyCount; nApplyIndex++) {
                try {
                    logger.info("同步第{}条数据", nApplyIndex + 1);
                    // 解析申请单内容是否成功
                    boolean banalysis = true;
                    Map<String, String> applyInfoMap = applyInfoMaps.get(nApplyIndex);
                    ApplyInfo applyInfo = applyInfos.get(nApplyIndex);
                    if (null == applyInfo) {
                        resultDesc.append("解析申请单消息失败");
                        logger.error("解析申请单消息失败");
                        banalysis = false;
                    }
                    if (banalysis) {
                        // 入库
                        logger.info("入库:{}", JSONUtil.toJsonStr(applyInfo));
                        boolean singleInfo = syncSingleInfo(applyInfoMap, applyInfo, applyInfos, resultDesc);
                        if (singleInfo) {
                            commonService.getCommonMap(applyInfoMap, true, resultDesc);
                        }
                    } else {
                        logger.error("不走入库:{}", detail);
                        commonService.getCommonMap(applyInfoMap, false, resultDesc);
                    }
                } catch (Exception e) {
                    logger.error("同步申请单出现异常：{},detail:", e.getMessage(), detail);
                }
            }
        } else {
            logger.error("解析申请单消息失败：{}\n", applyContent);
            return false;
        }
        return true;
    }

    /**
     * 保存到数据库
     *
     * @param applyInfoMap
     * @param resultDesc
     * @return
     */
    public boolean syncSingleInfo(Map<String, String> applyInfoMap, ApplyInfo applyInfo, List<ApplyInfo> applyInfos, StringBuffer resultDesc) {
        // 写入数据库是否成功
        boolean bWriteSucc = false;
        try {
            if (!convertSpecialField(applyInfoMap, applyInfo, resultDesc)) {
                logger.error("解析申请单字段出错");
                if (StringUtils.isEmpty(resultDesc.toString())) {
                    resultDesc.append("解析申请单字段出错");
                }
                return false;
            }
            if ("开单".equals(applyInfo.getApply().getApplyStatus())
                    || applyInfo.getApply().getChargeFlag().equals("0")) {

                boolean bCheckSucc = isApplyDataValid(applyInfo, resultDesc);
                if (!bCheckSucc) {
                    logger.error("无效的申请单信息：" + resultDesc.toString());
                    resultDesc.append("解析申请单消息失败:" + resultDesc);
                    return false;
                }
                if (StringUtils.isEmpty(applyInfo.getApply().getExamClass())) {
                    String strExamClass = matchExamClass(applyInfo);
                    if (StringUtils.isEmpty(strExamClass)) {
                        logger.error("无效的申请类别:" + applyInfo.getApply().getReqExamClass());
                        resultDesc.append("无效的申请类别:" + applyInfo.getApply().getReqExamClass());
                        return false;
                    }
                    applyInfo.getApply().setExamClass(strExamClass);
                    for (int nItemIndex = 0; nItemIndex < applyInfo.getApplyItemList().size(); nItemIndex++) {
                        applyInfo.getApplyItemList().get(nItemIndex).setExamClass(strExamClass);
                    }
                }
                // 如果医嘱内容过长 截取最前的2000个字符-否则会保存失败
                if (StringUtils.isNotBlank(applyInfo.getApply().getClinSymp())
                        && applyInfo.getApply().getClinSymp().length() > 2000) {
                    applyInfo.getApply().setClinSymp(applyInfo.getApply().getClinSymp().substring(0, 2000));
                }
                // 开单状态01
                applyInfo.getApply().setApplyStatus("01");
                bWriteSucc = writeToPacs(applyInfo, applyInfos);
                if (bWriteSucc) {
                    logger.info(String.format("同步申请单成功，ApplyNo(%s)", applyInfo.getApply().getApplyNo()));
                } else {
                    logger.info(String.format("同步申请单写入数据库失败，ApplyNo(%s)", applyInfo.getApply().getApplyNo()));
                    resultDesc.append(String.format("同步申请单写入数据库失败，ApplyNo(%s)", applyInfo.getApply().getApplyNo()));
                }
            } else if ("退费".equals(applyInfo.getApply().getApplyStatus())) {
                bWriteSucc = deleteApply(applyInfo.getApply().getApplyNo());
                if (bWriteSucc) {
                    logger.info("删除申请单成功：" + applyInfo.getApply().getApplyNo());
                } else {
                    logger.info("删除申请单失败：" + applyInfo.getApply().getApplyNo());
                    resultDesc.append("删除申请单失败：" + applyInfo.getApply().getApplyNo());
                }
            } else {
                resultDesc.append("该状态申请单不执行操作：" + applyInfo.getApply().getApplyStatus());
                logger.info("该状态申请单不执行操作：" + applyInfo.getApply().getApplyStatus());
                return false;
            }
        } catch (Exception e) {
            logger.error("申请单同步出错：" + e.getMessage(), e);
            resultDesc.append("申请单同步失败，请检查必要的入参；");
        }
        return bWriteSucc;
    }


    /**
     * 解析xml消息并设置到 ApplyInfo 对象上
     *
     * @param isTj
     * @param infoMap
     * @param applyInfo
     */
    private void convertApplyInfo(boolean isTj, Map<String, String> infoMap, ApplyInfo applyInfo) {
        ExamApply examApply = new ExamApply();
        examApply.setApplyNo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "apply_no", infoMap));
        examApply.setSickId(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "sick_id", infoMap));
        examApply.setMotherSickId(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "mother_sick_id", infoMap));
        examApply.setSickIdOld(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "sick_id_old", infoMap));
        examApply.setOutpatientNo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "outpatient_no", infoMap));
        examApply.setOutRegNo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "out_reg_no", infoMap));
        examApply.setInpatientNo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "inpatient_no", infoMap));
        examApply.setVisitId(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "visit_id", infoMap));

        // 将卡号和id设置成一样的值
        examApply.setIcCard(examApply.getSickId());
        //examApply.setIcCard(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "ic_card", infoMap));

        examApply.setMiCard(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "mi_card", infoMap));
        examApply.setIdentityCard(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "identity_card", infoMap));
        examApply.setName(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "name", infoMap));
        examApply.setFirstPhonetic(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "first_phonetic", infoMap));
        examApply.setSex(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "sex", infoMap));
        examApply.setBirthDate(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "birth_date", infoMap));
        examApply.setBirthTime(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "birth_time", infoMap));
        examApply.setAge(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "age", infoMap));
        examApply.setHeight(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "height", infoMap));
        examApply.setWeight(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "weight", infoMap));
        examApply.setBirthPlace(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "birth_place", infoMap));
        examApply.setDegree(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "degree", infoMap));
        examApply.setChargeType(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "charge_type", infoMap));
        examApply.setMailingAddress(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "mailing_address", infoMap));
        examApply.setZipCode(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "zip_code", infoMap));
        examApply.setPhoneNumber(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "phone_number", infoMap));
        examApply.setPatientSource(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "patient_source", infoMap));
        examApply.setPriorityOrder(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "priority_order", infoMap));

        examApply.setExamClass(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "exam_class", infoMap));

        //examApply.setExamSubclass(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "exam_sub_class", infoMap));
        examApply.setExamGroup(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "exam_group", infoMap));
        examApply.setReqDept(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_dept", infoMap));
        examApply.setReqDeptName(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_dept_name", infoMap));
        examApply.setReqPhysicianCode(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_physician_code", infoMap));
        examApply.setReqPhysician(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_physician", infoMap));
        examApply.setReqWardCode(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_ward_code", infoMap));
        examApply.setReqWardName(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_ward_name", infoMap));
        examApply.setNurseUnit(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "nurse_unit", infoMap));
        examApply.setBedNo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "bed_no", infoMap));
        examApply.setReqDate(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_date", infoMap));
        examApply.setReqTime(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_time", infoMap));
        examApply.setScheduledDate(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "scheduled_date", infoMap));
        examApply.setScheduledTime(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "scheduled_time", infoMap));
        examApply.setPhysSign(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "phys_sign", infoMap));
        examApply.setClinSymp(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "clin_symp", infoMap));
        examApply.setClinDiag(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "clin_diag", infoMap));
        examApply.setRelevantDiag(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "relevant_diag", infoMap));
        examApply.setRelevantLabTest(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "relevant_lab_test", infoMap));
        examApply.setExamMotive(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "exam_motive", infoMap));
        examApply.setReqMemo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_memo", infoMap));
        examApply.setNotice(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "notice", infoMap));
        examApply.setPerformDept(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "perform_dept", infoMap));
        examApply.setPerformDeptName(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "perform_dept_name", infoMap));
        examApply.setChargeFlag(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "charge_flag", infoMap));
        //examApply.setCost(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "costs", infoMap));
        examApply.setCharges(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "charges", infoMap));
        examApply.setMedRecord(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "med_record", infoMap));
        examApply.setLastMensesDate(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "last_menses_date", infoMap));
        examApply.setReqHospital(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_hospital", infoMap));
        examApply.setHospitalCode(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "hospital_code", infoMap));
        examApply.setFlags(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "flags", infoMap));
        examApply.setReserve1(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "reserve1", infoMap));
        //examApply.setNation(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "nation", infoMap));
        examApply.setReqExamClass(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "req_exam_class", infoMap));
        examApply.setApplyStatus(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "apply_status", infoMap));
        examApply.setReserve1(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "reserve1", infoMap));
        examApply.setReserve2(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "reserve2", infoMap));
        examApply.setReserve3(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "reserve3", infoMap));
        examApply.setTransTool(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY", "trans_tool", infoMap));

        ExamApplyItem applyItem = new ExamApplyItem();
        applyItem.setApplyNo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "apply_no", infoMap));
        applyItem.setItemNo("1");
        applyItem.setExamClass(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "exam_class", infoMap));
        applyItem.setItemCode(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "item_code", infoMap));
        applyItem.setItemName(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "item_name", infoMap));
        applyItem.setAmount("1");
        applyItem.setCost(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "cost", infoMap));
        applyItem.setCharge(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "charge", infoMap));
        applyItem.setOrderNo(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "order_no", infoMap));
        applyItem.setApplyId(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "apply_id", infoMap));
        applyItem.setRegAmount(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "reg_amount", infoMap));
        //applyItem.setItemId(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ITEM", "item_id", infoMap));

        List<ExamApplyItem> itemList = new ArrayList<>();
        itemList.add(applyItem);

        applyInfo.setApply(examApply);
        applyInfo.setApplyItemList(itemList);
        if (!StringUtils.isEmpty(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ORGAN", "organ_name", infoMap))) {
            String applyNo = fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ORGAN", "apply_no", infoMap);
            if (StringUtils.isEmpty(applyNo)) {
                applyNo = applyInfo.getApply().getApplyNo();
            }
            ExamApplyOrgan applyOrgan = new ExamApplyOrgan();
            applyOrgan.setApplyNo(applyNo);
            applyOrgan.setOrganNo("1");
            applyOrgan.setItemNo("1");
            applyOrgan.setOrganName(fieldConfigUtil.getFieldValue(isTj, "EXAM_APPLY_ORGAN", "organ_name", infoMap));
            List<ExamApplyOrgan> organList = new ArrayList<>();
            organList.add(applyOrgan);
            applyInfo.setApplyOrganList(organList);
        }
    }


    private boolean convertSpecialField(Map<String, String> infoMap, ApplyInfo applyInfo, StringBuffer resultDesc) {
        String strReqDate = "";
        String strReqTime = "";

        String strReqDateTime = applyInfo.getApply().getReqDate();
        if (StringUtils.isEmpty(strReqDateTime)) {
            strReqDate = DateUtils.getCurrentDate();
            strReqTime = DateUtils.getCurrentTime();
        } else if (strReqDateTime.length() == 19) {
            strReqDate = strReqDateTime.substring(0, 10);
            strReqTime = strReqDateTime.substring(11, 19);
        }
        applyInfo.getApply().setReqDate(strReqDate);
        applyInfo.getApply().setReqTime(strReqTime);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");
        String scheduledDateTime = applyInfo.getApply().getScheduledDate();
        if (StringUtils.isNotEmpty(scheduledDateTime)) {
            try {
                Date parse = sdf.parse(scheduledDateTime);
                applyInfo.getApply().setScheduledDate(sdfDate.format(parse));
                applyInfo.getApply().setScheduledTime(sdfTime.format(parse));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        if (!StringUtils.isEmpty(applyInfo.getApply().getBirthDate())) {
            applyInfo.getApply().setBirthDate(applyInfo.getApply().getBirthDate());


            if (StringUtils.isEmpty(applyInfo.getApply().getAge())) {
                applyInfo.getApply().setAge(DateUtils.getAge(applyInfo.getApply().getBirthDate()));
            }
        }


        if ("1".equals(applyInfo.getApply().getPriorityOrder())) {
            applyInfo.getApply().setPriorityOrder("急诊");
        } else {
            applyInfo.getApply().setPriorityOrder("普通");
        }
        String visitId = applyInfo.getApply().getVisitId();
        /* 376 */
        if (StringUtils.isNotEmpty(visitId)) {
            /* 377 */
            visitId = addZeroForNum(visitId, 3);
            /* 378 */
            applyInfo.getApply().setVisitId(visitId);
        }
        /* 385 */
        applyInfo.getApply().setHospitalCode(applyMQConfig.getHospCode());
        /* 386 */
        applyInfo.getApply().setReqHospital("成都市第一人民医院");
        /* 387 */
        return true;
    }

    public static void main(String[] args) {
        String s = "[{\"performDept\":[\"2AD01304006101\",\"2AD01305001103\"],\"itemCodes\":[\"JC00361\",\"JC00498\"],\"source\":[\"门诊\",\"住院\"],\"priority\":[\"普通\",\"急诊\"]}]";

        List<AutoScheduleProperties.AutoScheduleConfigItem> configItems = JsonUtil.json2List(s, AutoScheduleProperties.AutoScheduleConfigItem.class);
        System.out.println(configItems);
    }


    public static String addZeroForNum(String str, int strLength) {
        /* 400 */
        int strLen = str.length();
        /* 401 */
        if (strLen < strLength) {
            /* 402 */
            while (strLen < strLength) {
                /* 403 */
                StringBuffer sb = new StringBuffer();
                /* 404 */
                sb.append("0").append(str);
                /* 405 */
                str = sb.toString();
                /* 406 */
                strLen = str.length();
            }
        }
        /* 409 */
        return str;
    }


    /**
     * 保存到数据库落库
     *
     * @param applyInfo
     * @return
     */
    private boolean writeToPacs(ApplyInfo applyInfo, List<ApplyInfo> applyInfos) {
        int nRes = examApplyMapper.exist(applyInfo.getApply());

        /**
         * 根据检查项目编号
         * 查询检查项目名称，并设置到检查申请项目
         */
        String itemCode = applyInfo.getApplyItemList().get(0).getItemCode();
        if (!StringUtils.isEmpty(itemCode)) {
            DictExamItem examItem = dictExamItemMapper.findByCode(itemCode);
            if (Objects.nonNull(examItem)) {
                applyInfo.getApply().setExamClass(examItem.getExamClass());
                for (ExamApplyItem item : applyInfo.getApplyItemList()) {
                    item.setExamClass(examItem.getExamClass());
                }
            }
        }

        // 保存逻辑
        if (nRes > 0) {
            nRes = examApplyMapper.myUpdate(applyInfo.getApply());
        } else {
            nRes = examApplyMapper.save(applyInfo.getApply());
        }

        if (nRes == 0) {
            return false;
        }
        ExamApplyItem examApplyItemDel = new ExamApplyItem();
        examApplyItemDel.setApplyNo(applyInfo.getApply().getApplyNo());
        examApplyItemMapper.delete(examApplyItemDel);

        for (ExamApplyItem examApplyItem : applyInfo.getApplyItemList()) {
            examApplyItem.setApplyNo(applyInfo.getApply().getApplyNo());
            examApplyItem.setExamClass(applyInfo.getApply().getExamClass());
            examApplyItem.setChargeFlag(applyInfo.getApply().getChargeFlag());
            nRes = examApplyItemMapper.save(examApplyItem);
            if (nRes == 0) {
                return false;
            }
        }

        //if (applyInfo.getApplyOrganList() != null && applyInfo.getApplyOrganList().size() > 0) {
        if (CollectionUtils.isNotEmpty(applyInfo.getApplyOrganList())) {
            ExamApplyOrgan examApplyOrganDel = new ExamApplyOrgan();
            examApplyOrganDel.setApplyNo(applyInfo.getApply().getApplyNo());
            examApplyOrganMapper.delete(examApplyOrganDel);
            for (ExamApplyOrgan examApplyOrgan : applyInfo.getApplyOrganList()) {
                nRes = examApplyOrganMapper.save(examApplyOrgan);
                if (nRes == 0) {
                    return false;
                }
            }
        }
        if (examApplyPatientMapper.exist(applyInfo.getApply()) > 0) {
            nRes = examApplyPatientMapper.update(applyInfo.getApply());
        } else {
            nRes = examApplyPatientMapper.save(applyInfo.getApply());
        }
        if (nRes == 0) {
            return false;
        }

        // region 根据条件自动预约
        try {
            List<AutoScheduleProperties.AfterSaveConfigItem> afterSave = applyMQConfig.getAutoSchedule().getAfterSaveConfig();
            // 检查类别是否是入库后自动预约
            int count = applyInfos.size();

            // 如果入库条数大于1 就按照类型分组，通类型的数量大于1的就不自动预约
            if (count > 1) {
                Map<String, Long> groupCount = applyInfos.stream()
                        .filter(x -> null != x && null != x.getApply() && null != x.getApply().getReqExamClass())
                        .collect(Collectors.groupingBy(y -> y.getApply().getReqExamClass(), Collectors.counting()));

                count = groupCount.get(applyInfo.getApply().getReqExamClass()).intValue();
            }
            boolean flag = false;
            boolean multiFlag = false;
            if (CollectionUtils.isNotEmpty(afterSave)) {
                AutoScheduleProperties.AfterSaveConfigItem configItem = afterSave.stream()
                        .filter(x -> x.getExamClass().contains(applyInfo.getApply().getReqExamClass()))
                        .findFirst().orElse(null);
                flag = Objects.nonNull(configItem);
                if (flag) {
                    multiFlag = configItem.getPerformDept().contains(applyInfo.getApply().getPerformDept());
                }
            }
            // 判断是否需要自动预约
            if (multiFlag || (count <= 1 && flag)) {
                // 获取需要自动预约的配置
                List<AutoScheduleProperties.AutoScheduleConfigItem> configItems = applyMQConfig.getAutoSchedule().getConfigItems();
                if (CollectionUtils.isNotEmpty(configItems)) {
                    AutoScheduleProperties.AutoScheduleConfigItem configItem = configItems.stream()
                            // 检查诊室
                            .filter(x -> x.getPerformDept().contains(applyInfo.getApply().getPerformDept()))
                            // 检查项目code
                            .filter(y -> y.getItemCodes().contains(applyInfo.getApplyItemList().get(0).getItemCode()))
                            // 患者来源 如果没配置就不过滤
                            .filter(y -> CollectionUtils.isEmpty(y.getSource()) || y.getSource().contains(applyInfo.getApply().getPatientSource()))
                            // 患者优先级 如果没配置就不过滤
                            .filter(y -> CollectionUtils.isEmpty(y.getPriority()) || y.getPriority().contains(applyInfo.getApply().getPriorityOrder()))
                            .findFirst().orElse(null);
                    // 需要自动预约的，创建新的线程进行预约操作，不然影响数据入库
                    if (Objects.nonNull(configItem)) {
                        // 加入到队列里面进行自动预约操作
                        executor.execute(() -> {
                            try {
                                logger.info("自动预约-after-save，开始预约:{}", applyInfo.getApply().getApplyNo());
                                autoSchedule(applyInfo.getApply().getApplyNo());
                            } catch (Exception e) {
                                logger.error("自动预约 autoSchedule，error", e);
                            } finally {
                                logger.info("自动预约-after-save，完成预约:{}", applyInfo.getApply().getApplyNo());
                            }
                        });
                    }
                }
            }
        } catch (Exception e) {
            logger.error("入库成功，自动预约异常", e);
        }

        //endregion

        return true;
    }

    /**
     * 检查申请单入库数据信息是否完整
     *
     * @param applyInfo
     * @param errorInfo
     * @return
     */
    private boolean isApplyDataValid(ApplyInfo applyInfo, StringBuffer errorInfo) {
        boolean bValid = true;

        if (StringUtils.isEmpty(applyInfo.getApply().getApplyNo())) {
            bValid = false;
            errorInfo.append("单据号不能为空;");
        }
        if (StringUtils.isEmpty(applyInfo.getApply().getSickId())) {
            bValid = false;
            errorInfo.append("病人ID不能为空;");
        }
        if (StringUtils.isEmpty(applyInfo.getApply().getName())) {
            bValid = false;
            errorInfo.append("姓名不能为空;");
        }
        if (StringUtils.isEmpty(applyInfo.getApply().getSex())) {
            bValid = false;
            errorInfo.append("性别不能为空;");
        }
        if (StringUtils.isEmpty(applyInfo.getApply().getBirthDate())) {
            bValid = false;
            errorInfo.append("出生日期不能为空;");
        }

        if (applyInfo.getApplyItemList().size() == 0) {
            bValid = false;
            errorInfo.append("检查项目不能为空;");
        }
        if (StringUtils.isEmpty(applyInfo.getApply().getReqDeptName())) {
            bValid = false;
            errorInfo.append("申请科室不能为空;");
        }
        for (ExamApplyItem examApplyItem : applyInfo.getApplyItemList()) {
            if (StringUtils.isEmpty(examApplyItem.getItemName())) {
                bValid = false;
                errorInfo.append("检查项目名称不能为空;");
                break;
            }
        }
        return bValid;
    }


    private String matchExamClass(ApplyInfo applyInfo) {
        String examClass = null;

        if ("0".equals("1")) {
            Map<String, String> map = new HashMap<>();
            map.put("deptName", applyInfo.getApply().getPerformDeptName());
            map.put("itemName", applyInfo.getApplyItemList().get(0).getItemName());
            map.put("examClass", "");
            examApplyMapper.getExamClass(map);
            examClass = map.get("examClass");
        } else {
            String classMap = applyMQConfig.getExamClassMap();
            if (!StringUtils.isEmpty(classMap)) {
                Map<String, Object> mapVs = DataTrans.StringToMap(classMap);
                examClass = (String) mapVs.get(applyInfo.getApply().getReqExamClass());
            }
        }
        return examClass;
    }


    private boolean deleteApply(String applyNo) {
        ExamSysLog examSysLog = new ExamSysLog();
        ExamApplyItem itemDelete = new ExamApplyItem();
        itemDelete.setApplyId(applyNo);
        int exist = examApplyItemMapper.existByApplyId(itemDelete);
        examApplyItemMapper.deleteByApplyId(itemDelete);
        if (exist == 1) {
            ExamApplyOrgan organDelete = new ExamApplyOrgan();
            organDelete.setApplyNo(applyNo);
            examApplyOrganMapper.delete(organDelete);

            examApplyMapper.delete(applyNo);
            examScheduleMapper.delete(applyNo);
            examSysLog.setDescription("删除exam_apply表记录");
        } else {
            examSysLog.setDescription("只删除exam_apply_item表记录");
        }
        examSysLog.setOperateName("删除申请单");
        examSysLog.setModuleName("申请单接口");
        examSysLog.setExamNo(applyNo);
        examSysLogMapper.addSysLog(examSysLog);
        return true;
    }


    /**
     * 调用管理端接口进行自动预约操作
     *
     * @param applyNo
     */
    public void autoSchedule(String applyNo) {
        String toDay = DateUtils.getCurrDate();
        ScheduleApmReqVO reqVO = new ScheduleApmReqVO();
        reqVO.setApplyNo(applyNo);
        reqVO.setMergeNo(applyNo + "-1");
        reqVO.setScheduleDate(toDay);
        reqVO.setTerminalType("A");
        reqVO.setHospitalCode("H05");

        List<ScheduleApmResVO> apmList = getApmList(reqVO);
        if (CollectionUtils.isNotEmpty(apmList)) {
            // 过滤掉不能用的时段
            apmList = apmList.stream()
                    .filter(x -> "1".equals(x.getEnabled()))
                    .filter(x -> {
                        Pattern pattern = Pattern.compile("\\d+");
                        Matcher matcher = pattern.matcher(x.getRemainCount());
                        String count = "0";
                        if (matcher.find()) {
                            count = matcher.group();
                        }
                        return Integer.parseInt(count) > 0;
                    })
                    .collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(apmList)) {
            logger.error("自动预约->没有获取到可预约时段2:{}", JsonUtil.toJson(reqVO));
            return;
        }
        // 选择第一个时间段
        ScheduleApmResVO apmVO = apmList.get(0);
        reqVO.setScheduleApm(apmVO.getApm());
        reqVO.setStartTime(apmVO.getStartTime());
        reqVO.setEndTime(apmVO.getEndTime());
        // 锁号
        ScheduleCommonResVO setRes = getApmSet(reqVO);
        if (!"0".equals(setRes.getStatus())) {
            logger.error("自动预约->锁号失败:{},{}", JsonUtil.toJson(reqVO), JsonUtil.toJson(setRes));
            return;
        }
        // 确认预约
        reqVO.setScheduleDate(null);
        reqVO.setScheduleApm(null);
        reqVO.setStartTime(null);
        reqVO.setEndTime(null);
        ScheduleCommonResVO confirmRes = getApmConfirm(reqVO);
        if (!"0".equals(confirmRes.getStatus())) {
            logger.error("自动预约->确认预约:{}", JsonUtil.toJson(reqVO));
        } else {
            logger.info("自动预约->自动预约成:{}", JsonUtil.toJson(reqVO));
        }
    }

    /**
     * 获取可预约时段
     *
     * @param reqVO
     * @return
     */
    private List<ScheduleApmResVO> getApmList(ScheduleApmReqVO reqVO) {
        List<ScheduleApmResVO> apms = null;
        String urlPath = "/scheduleApi/schedule/apm/list";
        // 推送http请求
        ScheduleCommonResVO resVO = sendScheduleReq(urlPath, reqVO);
        if ("0".equals(resVO.getStatus()) && Objects.nonNull(resVO.getResult())) {
            String dataRet = JsonUtil.toJson(resVO.getResult());
            apms = JsonUtil.json2List(dataRet, ScheduleApmResVO.class);
        }
        return apms;
    }

    /**
     * 获取可预约时段
     *
     * @param reqVO
     * @return
     */
    private ScheduleCommonResVO getApmSet(ScheduleApmReqVO reqVO) {
        // List<ScheduleApmResVO> apms = null;
        String urlPath = "/scheduleApi/schedule/apm/set";
        // 推送http请求
        ScheduleCommonResVO resVO = sendScheduleReq(urlPath, reqVO);
        return resVO;
    }

    /**
     * 获取可预约时段
     *
     * @param reqVO
     * @return
     */
    private ScheduleCommonResVO getApmConfirm(ScheduleApmReqVO reqVO) {
        //List<ScheduleApmResVO> apms = null;
        String urlPath = "/scheduleApi/schedule/apm/confirm";
        // 推送http请求
        ScheduleCommonResVO resVO = sendScheduleReq(urlPath, reqVO);
        return resVO;
    }

    /**
     * 获取可预约时段
     *
     * @param reqVO
     * @return
     */
    String manageToken = "";

    // Map<String, String> manageHeaderMap = new HashMap<>();
    private String getManageToken() {
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(manageToken)) {
            return manageToken;
        }
        String urlPath = "/scheduleApi/login";
        String params = "{\"username\": \"" + applyMQConfig.getAutoSchedule().getUserName() + "\",\"password\": \"" + applyMQConfig.getAutoSchedule().getUserPwd() + "\"}";
        Map<String, String> headerMap = new HashMap<>();
        // 推送http请求
        String result = HttpUtils.doPostJson(applyMQConfig.getAutoSchedule().getUrl() + urlPath, params, headerMap);
        ScheduleCommonResVO res = JsonUtil.json2Bean(result, ScheduleCommonResVO.class);
        if ("0".equals(res.getStatus())) {
            Map map = JsonUtil.json2Bean(JsonUtil.toJson(res.getResult()), Map.class);
            manageToken = String.valueOf(map.get("token"));
        }
        return manageToken;
    }


    /**
     * 获取可预约时段
     *
     * @param reqVO
     * @return
     */
    private ScheduleCommonResVO sendScheduleReq(String urlPath, ScheduleApmReqVO reqVO) {
        ScheduleCommonResVO res = null;
        String params = JsonUtil.toJson(reqVO);
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("token", manageToken);
        // 推送http请求
        String result = HttpUtils.doPostJson(applyMQConfig.getAutoSchedule().getUrl() + urlPath, params, headerMap);
        logger.info("url:{},result:{}", urlPath, result);
        res = JsonUtil.json2Bean(result, ScheduleCommonResVO.class);
        // 如果失效就重新获取token，再重新调用
        if ("102".equals(res.getStatus())) {
            manageToken = null;
            getManageToken();
            return sendScheduleReq(urlPath, reqVO);
        }
        return res;
    }
}